<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Study GraphQL</title>
  <style>
    span {
      margin: 0 4px;
    }

    button {
      margin: 0 10px;
    }

    input {
      margin-right: 10px;
    }

    .pointer {
      cursor: pointer;
    }

    .red {
      color: red;
    }

    .blue {
      color: blue;
    }
  </style>
</head>

<body>
  <div id="root"></div>
</body>
<script src="/react-dom.development.js/umd/react.development.js"></script>
<script src="/react-dom.development.js/umd/react-dom.development.js"></script>
<script src="/babel-standalone@6.26.0/babel.js"></script>
<script type="text/babel">
  const BUTTON_MAP = {
    add: '新增',
    edit: '提交'
  };

  function getUser(id) {
    const query = `query getUser($id: ID!) { 
      getUser(id: $id) {
        id,
        name,
        age
      }
    }`;

    const variables = { id };

    return new Promise((resolve, reject) => {
      fetch('/api/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
        body: JSON.stringify({
          query,
          variables,
        }),
      })
        .then((res) => res.json())
        .then((data) => {
          resolve(data);
        });
    })
  }

  function getUsers() {
    const query = `query getUsers { 
      getUsers {
        id,
        name,
        age
      }
    }`;

    return new Promise((resolve, reject) => {
      fetch('/api/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
        body: JSON.stringify({
          query,
        }),
      })
        .then((res) => res.json())
        .then((data) => {
          resolve(data)
        });
    });
  }

  function addUser(name, age) {
    const query = `mutation createUser($user: UserInput) { 
      createUser(user: $user)
    }`;

    const variables = {
      user: {
        name, age
      }
    };
    return new Promise((resolve, reject) => {
      fetch('/api/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
        body: JSON.stringify({
          query,
          variables
        }),
      })
        .then((res) => res.json())
        .then((data) => {
          resolve(data)
        });
    });
  }

  function updateUser(id, name, age) {
    const query = `mutation updateUser($id: ID!, $user: UserInput) { 
      updateUser(id: $id, user: $user)
    }`;

    const variables = {
      id,
      user: {
        name, age
      }
    };
    return new Promise((resolve, reject) => {
      fetch('/api/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
        body: JSON.stringify({
          query,
          variables
        }),
      })
        .then((res) => res.json())
        .then((data) => {
          resolve(data)
        });
    });
  }

  function deleteUser(id) {
    const query = `mutation deleteUser($id: ID!) { 
      deleteUser(id: $id)
    }`;

    const variables = {
      id
    };
    return new Promise((resolve, reject) => {
      fetch('/api/graphql', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
        body: JSON.stringify({
          query,
          variables
        }),
      })
        .then((res) => res.json())
        .then((data) => {
          resolve(data)
        });
    })
  }


  // 页面
  const UserPage = () => {
    const [userList, setUserList] = React.useState([]);
    const [userForm, setUserForm] = React.useState({ id: '', name: '', age: '', type: 'add' });
    const [isReload, setReload] = React.useState(false)
    const [id, setId] = React.useState('');
    React.useEffect(() => {
      refreshUserList();
    }, []);

    React.useEffect(() => {
      if (isReload) {
        refreshUserList();
      }
      setReload(false);
    }, [isReload]);

    React.useEffect(() => {
      if (id) {
        getUser(id).then(res => {
          const { data: { getUser: user } } = res;
          setUserForm({ type: 'edit', ...user });
        })
      }
    }, [id]);

    function refreshUserList() {
      getUsers().then(res => {
        const { data: { getUsers = [] } } = res;
        setUserList(getUsers);
      })
    }

    return (<div>
      <UserList userList={userList} setReload={setReload} setId={setId} />
      <UserOperator setUserForm={setUserForm} userForm={userForm} setReload={setReload} />
    </div>);
  };

  // 列表
  const UserList = (props) => {
    const { userList, setReload, setId } = props;
    const userItems = userList.map((user, index) => {
      return <UserItem key={user.id} user={user} setReload={setReload} setId={setId} />
    });
    return (<ul>{userItems}</ul>);
  };

  // 数据项
  const UserItem = (props) => {
    const { user, setReload, setId } = props;

    function handleDelete(id) {
      deleteUser(id).then(res => {
        const { data: { deleteUser: flag } } = res;
        if (flag) {
          setReload(true);
        }
      })
    }

    function handleEdit(id) {
      setId(id);
    }

    return (<li>
      {user.name}: {user.age}岁
      <span className="blue pointer" onClick={() => handleEdit(user.id)}>编辑</span>
      <span className="red pointer" onClick={() => handleDelete(user.id)}>删除</span>
    </li>);
  };

  // 新增
  const UserOperator = (props) => {
    const [id, setId] = React.useState('');
    const [name, setName] = React.useState('');
    const [age, setAge] = React.useState('');
    const { setUserForm, userForm, setReload } = props;

    function handleChange(e, cb) {
      cb(e.target.value)
    }

    function handleSubmit() {
      const { type } = userForm;
      if (type === 'edit') {
        updateUser(id, name, Number(age)).then(res => {
          const { data: { updateUser: flag } } = res;
          if (flag) {
            setReload(true);
            setId('');
            setName('');
            setAge('');
          } else {
            alert('更新失败');
          }
        })
      } else if (type === 'add') {
        if (name && age) {
          addUser(name, Number(age)).then(res => {
            const { data: { createUser: flag } } = res;
            if (flag) {
              setReload(true);
              setId('');
              setName('');
              setAge('');
            } else {
              alert('添加失败');
            }
          });
        }
      }
      setUserForm({ ...userForm, type: 'add' })
    }

    React.useEffect(() => {
      const { id, name, age } = userForm
      setId(id);
      setName(name);
      setAge(age);
    }, [userForm]);

    return (<div>
      <span>姓名:</span><input type="text" value={name} onChange={e => handleChange(e, setName)} />
      <span>年龄:</span><input type="number" value={age} onChange={e => handleChange(e, setAge)} />
      <button onClick={() => handleSubmit()}>{BUTTON_MAP[userForm.type]}</button>
    </div>)
  }

  const App = (props) => {
    return (<div><h2>{props.title}</h2><UserPage /></div>);
  };

  const root = document.getElementById('root');
  ReactDOM.render(<App title="A Simple GraphQL Demo With React Design By ataola, Have Fun!" />, root);
</script>

</html>